/* 
 * File:   connection.h
 * Author: james
 *
 * Created on 2011年3月31日, 下午12:56
 */

#ifndef CONNECTION_H
#define	CONNECTION_H

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/function.hpp>

#include <string>
#include <set>
#include <deque>

#include "command.h"
using namespace edm::common;

#include "message.h"

namespace edm
{
    namespace network
    {
        enum CONNNECTION_MODE{
            E_CON_ACTIVE = 0,
            E_CON_PASSIVE = 1,
        };
        
        //! predefine for callback error
        class connection_t;
        //! connection pointer typedef
        typedef boost::shared_ptr<connection_t> connection_ptr_t;
        //! connected event callback type, only for active mode
        typedef boost::function<void(connection_ptr_t)> callback_connect_t;        
        //! message event callback type
        typedef boost::function<void(connection_ptr_t, message_t&)> callback_handler_t;
        //! connection error callback type
        typedef boost::function<void(connection_ptr_t)> callback_error_t;
        
        //! connection type for active & passive mode
        class connection_t: public boost::enable_shared_from_this<connection_t>
        {
            enum {READ_BUFFER_LEN = 8192};
        public:
            explicit connection_t(boost::asio::io_service& io_service);
            explicit connection_t(boost::asio::io_service& io_service,
                                  const std::string& host, const std::string& port);
            ~connection_t();
            
            boost::asio::ip::tcp::socket& socket();
            
            //! default async read from connection, active mode will just connect first
            void start(callback_handler_t cb, callback_error_t cb_err, callback_connect_t cb_ok = 0);
            
            //! close connection
            void stop();
            
            //! get ip
            std::string local_address();
            std::string remote_address();
            //! write message
            void async_write(COMMANDER command, edm_uint64_t reserved, const char*  body);
            //! write message
            void async_write(COMMANDER command, edm_uint64_t reserved, std::string& body);            
            //! get cb hander
            callback_handler_t callback_handler();
            //! get cb error
            callback_error_t callback_error();
            //! get cb connect
            callback_connect_t callback_connect();
            //! connected
            bool connected();
        protected:
            void trigger_read();
            void trigger_write();
        private:
            //! sync_write
            void sync_write_i(COMMANDER command, edm_uint64_t reserved, std::string& body);            
            //! resolver
            void handle_resolve(const boost::system::error_code& error, 
                           boost::asio::ip::tcp::resolver::iterator endpoint_iterator); 
            //! connect
            void handle_connect(const boost::system::error_code& error,
                           boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
            //! reader header cb
            void handle_read_header(const boost::system::error_code& error, std::size_t bytes_transferred);
            
            //! reader body cb
            void handle_read_body(const boost::system::error_code& error, std::size_t bytes_transferred);
            
            //! write message cb
            void handle_write(const boost::system::error_code& error);
            
            //! handle error occur
            void handle_error(const boost::system::error_code& error);
            
        private:
            //! connection io service ref
            boost::asio::io_service& m_io_service;
            //! connection io service strand, ensure the connection's handlers are not called concurrently.
            boost::asio::io_service::strand m_strand;
            //! resolver to active connection
            boost::asio::ip::tcp::resolver m_resolver;
            //! socket for the connection.
            boost::asio::ip::tcp::socket m_socket;
            //! active host
            std::string m_host;
            //! active port
            std::string m_port;
            //! mode
            CONNNECTION_MODE m_mode;
            //! connected flag
            bool m_connected;
            //! remote address
            std::string m_remote_addr;
            //! writting flag
            bool m_writting_flag;
            //! read header buffer
            char  m_read_header_buffer[MESSAGE_HDR_MAX_LEN];
            //! read body buffer
            char  m_read_body_buffer[READ_BUFFER_LEN];
            //! read body left
            int             m_read_left_len;
            //! writting buffer
            std::string m_writting_raw;
            //! read message
            message_t                m_read_message;
            //! write message deque
            std::deque<message_t>    m_write_messages;
            //! callback_handler_t
            callback_handler_t       m_callback_handler;
            //! callback_error_t
            callback_error_t         m_callback_error;
            //! callback_connect_t
            callback_connect_t       m_callback_connect;
        };
        
    }
}

#endif	/* CONNECTION_H */

